"""生成标题编号

按行遍历 markdown 文档时，找到一个标题行就生成一个标题编号。

"""
from collections import defaultdict


class TitleSignError(Exception):
    # 从标题行中提取出的标题符号错误
    pass


class TitleNumber:
    """
    Exemple:
    --------
    >>>t = TitleNumber()
    >>>t.extend(["##", "###", "###", "##", "####", "###", "####"])
    >>>print(t.get_numbers())
    ['1', '1.1', '1.2', '2', '2.0.1', '2.1', '2.1.1']
    """

    def __init__(self):
        self._title_signs = []
        self._title_numbers = []
        self._init_map()
        self._title_sign_counter = defaultdict(int)
        self.max_level_sign = len(self._sign2number_map) + 1

    def _init_map(self):
        self._sign2number_map = {
            "#": 1,
            "##": 2,
            "###": 3,
            "####": 4,
            "#####": 5,
            "######": 6,
            "#######": 7
        }
        self._valid_keys = sorted(
            self._sign2number_map.keys(), key=lambda x: self._sign2number_map[x])

    def _check_sign(self, sign: str):
        if self._sign2number_map.get(sign, None) is None:
            return False
        return True

    def _get_number_from_counter(self, level: int):
        number_str = ".".join(
            [str(self._title_sign_counter[sign])
             for sign in self._valid_keys[:level]]
        )
        if level == 1:
            number_str += "."
        return number_str

    def zero_counter(self, level: int):
        for sign in self._valid_keys[level:]:
            self._title_sign_counter[sign] = 0

    def append(self, sign: str):
        """添加一个找到的标题符

        params: sign, 比如 '##' 代表二级标题
        return：number，对应的标题编号
        """
        if not self._check_sign(sign):
            raise TitleSignError()
        level = self._sign2number_map[sign]
        if level < self.max_level_sign:
            self.max_level_sign = level
        self.zero_counter(level)
        self._title_sign_counter[sign] += 1
        number_str = self._get_number_from_counter(level)
        self._title_signs.append(sign)
        self._title_numbers.append(number_str)

    def extend(self, signs: list):
        for s in signs:
            self.append(s)

    def get_numbers(self):
        numbers = []
        for i in self._title_numbers:
            n = i[(self.max_level_sign-1)*2:]
            if len(n) == 1:
                n += '.'
            numbers.append(n)
        return numbers


if __name__ == "__main__":
    t = TitleNumber()
    t.extend(["##", "###", "###", "##", "####", "###", "####"])
    print(t.get_numbers())
